#include "imagecreator.h"
#include "formatinfo.h"
#include "versioninfo.h"
#include "common/masking.h"
#include "common/stringutils.h"

#include <QImage>
#include <QColor>
#include <QRgb>

#include <QDebug>

namespace qrcode {

ImageCreator::ImageCreator()
{
    init();
}

ImageCreator::ImageCreator(int version, std::vector<char> bitstream)
    :version(version), bitstream(bitstream)
{
    //当前版本边的模块数
    nMods = 21 + 4*(version-1);
    StringUtils::PRINT("每边的模块数：", nMods);
    //qDebug() << "每边模块数：" << nMods;

    //默认放大系数
//    COE = 1;
    //模块默认像素
    nPix = 4;

    init();

}

void ImageCreator::init()
{
    //矫正图形中心模块坐标
    std::vector<int> vec;
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 18};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 22};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 26};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 34};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 22, 38};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 24, 42};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 26, 46};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 28, 50};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 54};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 32, 58};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 34, 62};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 26, 46, 66};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 26, 48, 70};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 26, 50, 74};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 54, 78};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 56, 82};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 58, 86};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 34, 62, 90};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 28, 50, 72, 94};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 26, 50, 74, 98};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 54, 78, 102};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 28, 54, 80, 106};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 32, 58, 84, 110};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 58, 86, 114};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 34, 62, 90, 118};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 26, 50, 74, 98, 122};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 54, 78, 102, 126};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 26, 52, 78, 104, 130};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 56, 82, 108, 134};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 34, 60, 86, 112, 138};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 58, 86, 1114, 142};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 34, 62, 90, 118, 146};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 54, 78, 102, 126, 150};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 24, 50, 76, 102, 128, 154};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 28, 54, 80, 106, 132, 158};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 32, 58, 84, 110, 136, 162};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 26, 54, 82, 110, 138, 166};
    coordinatesAlignPatterns.push_back(vec);
    vec = {6, 30, 58, 86, 114, 142, 170};
    coordinatesAlignPatterns.push_back(vec);
}

QImage ImageCreator::GeneratorPixelImg()
{
    //1.获得基础图形
    QImage img = BaseModuleMatrix();

    //2.Place the Data Bits
    PlaceDataBits(img);

    img.save("test_data.png");

    return img;
}

void ImageCreator::Creator()
{
    //生成像素为1的二维码图像
    QImage image = GeneratorPixelImg();
    image.save("nomask.png");

    //掩模处理
    Masking *qMasking = new Masking(version);
    qMasking->setInitImage(image);
    qMasking->setLockModule(lockModule);
    qMasking->MakeMasking();

    QImage maskedImg = qMasking->getFinalImage();
    int masknum = qMasking->getMaskNum();

    //格式信息编码
    FormatInfo *qformat = new FormatInfo();
    qformat->setErrorlevel(errorLevel);
    qformat->setMasknum(masknum);
    qformat->Creator();

    std::vector<int> formatbits = qformat->getFormatbitstream();

    //向图片中添加格式信息
    AddFormatInfo(maskedImg, formatbits);

    //添加版本信息
    if(version >= 7){
        VersionInfo *qver = new VersionInfo();
        qver->setVersion(version);
        qver->Creator();
        std::vector<int> versionbits =  qver->getVersionbitstream();

        AddVersionInfo(maskedImg, versionbits);
    }

    //生成图像
    QImage img = GenPicture(maskedImg, pic.getCOE());


    img.save(QString("%1%2.%3").arg(QString::fromStdString(pic.getFilepath()))
             .arg(QString::fromStdString(pic.getFilename()))
             .arg(QString::fromStdString(pic.getPicFormat())));

}

std::vector<std::pair<int, int> > ImageCreator::GetLockModule(int v)
{
    version = v;
    nMods = 21 + 4*(version-1);

    BaseModuleMatrix();

    return lockModule;
}

/**
 * @brief ImageCreator::GenPicture 放大图片
 * @param image 基础像素图片
 * @param coe   放大系数
 * @return      放大后的图片
 */
QImage ImageCreator::GenPicture(QImage &image, int coe)
{
    QImage img(nPix*coe*nMods+2*nPix, nPix*coe*nMods+2*nPix, QImage::Format_RGB32);
    img.fill(value_w);

    for(int i = 0; i < nMods; i++){
        for(int j = 0; j < nMods; j++){
            DrawSquarePix(img, image.pixelColor(i, j), nPix*coe*i+nPix, nPix*coe*j+nPix, nPix*coe);
        }
    }

    return img;
}

/**
 * @brief ImageCreator::DrawSquarePix 放大像素
 * @param image 原图
 * @param color 像素颜色
 * @param x     x坐标
 * @param y     y坐标
 * @param coe   放大系数
 */
void ImageCreator::DrawSquarePix(QImage &image, QColor color,
                                 int x, int y, int coe)
{
    for(int i = x; i < x+coe; i++){
        for(int j = y; j < y+coe; j++){
            //qDebug() << "放大后位置：" << x << ", " << y;
            image.setPixelColor(i, j, color);
        }
    }
}

QImage ImageCreator::BaseModuleMatrix()
{
    //1.创建图形
    QImage image(nMods, nMods, QImage::Format_RGB32);
    image.fill(Qt::red);

    //2.Add the Finder Patterns
    AddFinderPatterns(image, nMods);

    //4.Add the Alignment Patterns
    AddAlignmentPatterns(image, version);

    //5.Add the Timing Patterns
    AddTimingPatterns(image);

    //6.Add the Dark Module and Reserved Areas
    //Dark Module
    image.setPixelColor(8, 4*version+9, value_b);
    lockModule.push_back(std::make_pair(8, 4*version+9));
    //Reserve Areas
    AddReservedAreas(image);

    //image.save("test_base.png");

    return image;
}

void ImageCreator::AddFinderPatterns(QImage &image, int &nMods)
{
    //7 module
    for(int i = 0; i < 7; i++){

        image.setPixelColor(0, i, value_b);
        image.setPixelColor(6, i, value_b);
        image.setPixelColor(i, 0, value_b);
        image.setPixelColor(i, 6, value_b);

        image.setPixelColor(i, nMods-1, value_b);
        image.setPixelColor(i, nMods-7, value_b);
        image.setPixelColor(0, nMods-i-1, value_b);
        image.setPixelColor(6, nMods-i-1, value_b);

        image.setPixelColor(nMods-1, i, value_b);
        image.setPixelColor(nMods-7, i, value_b);
        image.setPixelColor(nMods-i-1, 0, value_b);
        image.setPixelColor(nMods-i-1, 6, value_b);
    }

    //5 module
    for(int i = 1; i < 6; i++){
        image.setPixelColor(1, i, value_w);
        image.setPixelColor(5, i, value_w);
        image.setPixelColor(i, 1, value_w);
        image.setPixelColor(i, 5, value_w);

        image.setPixelColor(i, nMods-2, value_w);
        image.setPixelColor(i, nMods-6, value_w);
        image.setPixelColor(1, nMods-i-1, value_w);
        image.setPixelColor(5, nMods-i-1, value_w);

        image.setPixelColor(nMods-2, i, value_w);
        image.setPixelColor(nMods-6, i, value_w);
        image.setPixelColor(nMods-i-1, 1, value_w);
        image.setPixelColor(nMods-i-1, 5, value_w);
    }

    //3 module
    for(int i = 2; i < 5; i++){
        image.setPixelColor(2, i, value_b);
        image.setPixelColor(4, i, value_b);
        image.setPixelColor(i, 2, value_b);
        image.setPixelColor(i, 4, value_b);
        image.setPixelColor(3, 3, value_b);

        image.setPixelColor(i, nMods-3, value_b);
        image.setPixelColor(i, nMods-5, value_b);
        image.setPixelColor(2, nMods-i-1, value_b);
        image.setPixelColor(4, nMods-i-1, value_b);
        image.setPixelColor(3, nMods-4, value_b);

        image.setPixelColor(nMods-3, i, value_b);
        image.setPixelColor(nMods-5, i, value_b);
        image.setPixelColor(nMods-i-1, 2, value_b);
        image.setPixelColor(nMods-i-1, 4, value_b);
        image.setPixelColor(nMods-4, 3, value_b);
    }

    //3.Add the Separators
    for(int i = 0; i < 8; i++){
        image.setPixelColor(7, i, value_w);
        image.setPixelColor(i, 7, value_w);

        image.setPixelColor(i, nMods-8, value_w);
        image.setPixelColor(7, nMods-i-1, value_w);

        image.setPixelColor(nMods-8, i, value_w);
        image.setPixelColor(nMods-i-1, 7, value_w);
    }
}

void ImageCreator::AddAlignmentPatterns(QImage &image, int &version)
{
    std::vector<int> coordinates = coordinatesAlignPatterns.at(version-1);
    for(int i = 0; i < coordinates.size(); i++){
        for(int j = 0; j < coordinates.size(); j++){
            if(!WithinFinderPatterns(coordinates.at(i), coordinates.at(j))){
                //qDebug() << "Without: (" << coordinates.at(i) << ", " << coordinates.at(j) << ")";
                DrawAlignmentPatterns(image, coordinates.at(i), coordinates.at(j));
            }
        }
    }
}

void ImageCreator::AddTimingPatterns(QImage &image)
{
    bool flag = true;
    for(int i = 8; i < nMods-8; i++){
        if(!IsLockModule(i, 6)){
            if(flag){
                image.setPixelColor(i, 6, value_b);
            } else {
                image.setPixelColor(i, 6, value_w);
            }
        }
        if(!IsLockModule(6, i)){
            if(flag){
                image.setPixelColor(6, i, value_b);
            } else {
                image.setPixelColor(6, i, value_w);
            }
        }
        flag = !flag;
    }

    //add lockmodule
    for(int i = 8; i < nMods-8; i++){
        if(!IsLockModule(i, 6)){
            lockModule.push_back(std::make_pair(i, 6));
        }
        if(!IsLockModule(6, i)){
            lockModule.push_back(std::make_pair(6, i));
        }
    }
}

/**
 * @brief ImageCreator::AddReservedAreas 添加保留区域（格式信息、版本信息区域）
 * @param image
 *
 * 注意：1~6版本没有版本信息区
 */
void ImageCreator::AddReservedAreas(QImage &image)
{
    //1.Reserve the Format Information Area
    for(int i = 0; i <= 8; i++){
        if(!IsLockModule(i, 8)){
            image.setPixelColor(i, 8, value_y);
            lockModule.push_back(std::make_pair(i, 8));
        }
        if(!IsLockModule(8, i)){
            image.setPixelColor(8, i, value_y);
            lockModule.push_back(std::make_pair(8, i));
        }
    }
    for(int i = 0; i < 7; i++){
        image.setPixelColor(8, nMods-1-i, value_y);
        image.setPixelColor(nMods-i-1, 8, value_y);
        lockModule.push_back(std::make_pair(8, nMods-i-1));
        lockModule.push_back(std::make_pair(nMods-i-1, 8));
    }
    image.setPixelColor(nMods-8, 8, value_y);
    lockModule.push_back(std::make_pair(nMods-8, 8));

    //2.Reserve the Version Information Area
    if(version > 6){
        for(int i = 0; i < 6; i++){
            for(int j = 0; j < 3; j++){
                image.setPixelColor(i, nMods-j-9, value_y);
                image.setPixelColor(nMods-j-9, i, value_y);
                lockModule.push_back(std::make_pair(i, nMods-j-9));
                lockModule.push_back(std::make_pair(nMods-j-9, i));
            }
        }
    }
}

void ImageCreator::DrawAlignmentPatterns(QImage &image, int &x, int &y)
{
    image.setPixelColor(x, y, value_b);

    image.setPixelColor(x-1, y-1, value_w);
    image.setPixelColor(x, y-1, value_w);
    image.setPixelColor(x+1, y-1, value_w);
    image.setPixelColor(x-1, y, value_w);
    image.setPixelColor(x+1, y, value_w);
    image.setPixelColor(x-1, y+1, value_w);
    image.setPixelColor(x, y+1, value_w);
    image.setPixelColor(x+1, y+1, value_w);

    image.setPixelColor(x-2, y-2, value_b);
    image.setPixelColor(x-1, y-2, value_b);
    image.setPixelColor(x, y-2, value_b);
    image.setPixelColor(x+1, y-2, value_b);
    image.setPixelColor(x+2, y-2, value_b);
    image.setPixelColor(x-2, y-1, value_b);
    image.setPixelColor(x+2, y-1, value_b);
    image.setPixelColor(x-2, y, value_b);
    image.setPixelColor(x+2, y, value_b);
    image.setPixelColor(x-2, y+1, value_b);
    image.setPixelColor(x+2, y+1, value_b);
    image.setPixelColor(x-2, y+2, value_b);
    image.setPixelColor(x-1, y+2, value_b);
    image.setPixelColor(x, y+2, value_b);
    image.setPixelColor(x+1, y+2, value_b);
    image.setPixelColor(x+2, y+2, value_b);

    std::pair<int, int> p;
    for(int k1 = x-2; k1 <= x+2; k1++){
        for(int k2 = y-2; k2 <= y+2; k2++){
//            p = std::make_pair
            lockModule.push_back(std::make_pair(k1, k2));
        }
    }
}

void ImageCreator::AddFormatInfo(QImage &image, std::vector<int> info)
{
    //1.Add the Format Information Area 1
    DrawPixelColor(image, info, 0, 8, nMods-1);
    DrawPixelColor(image, info, 1, 8, nMods-2);
    DrawPixelColor(image, info, 2, 8, nMods-3);
    DrawPixelColor(image, info, 3, 8, nMods-4);
    DrawPixelColor(image, info, 4, 8, nMods-5);
    DrawPixelColor(image, info, 5, 8, nMods-6);
    DrawPixelColor(image, info, 6, 8, nMods-7);
    DrawPixelColor(image, info, 7, nMods-8, 8);
    DrawPixelColor(image, info, 8, nMods-7, 8);
    DrawPixelColor(image, info, 9, nMods-6, 8);
    DrawPixelColor(image, info, 10, nMods-5, 8);
    DrawPixelColor(image, info, 11, nMods-4, 8);
    DrawPixelColor(image, info, 12, nMods-3, 8);
    DrawPixelColor(image, info, 13, nMods-2, 8);
    DrawPixelColor(image, info, 14, nMods-1, 8);
    //2.Add the Format Information Area 2
    DrawPixelColor(image, info, 0, 0, 8);
    DrawPixelColor(image, info, 1, 1, 8);
    DrawPixelColor(image, info, 2, 2, 8);
    DrawPixelColor(image, info, 3, 3, 8);
    DrawPixelColor(image, info, 4, 4, 8);
    DrawPixelColor(image, info, 5, 5, 8);
    DrawPixelColor(image, info, 6, 7, 8);
    DrawPixelColor(image, info, 7, 8, 8);
    DrawPixelColor(image, info, 8, 8, 7);
    DrawPixelColor(image, info, 9, 8, 5);
    DrawPixelColor(image, info, 10, 8, 4);
    DrawPixelColor(image, info, 11, 8, 3);
    DrawPixelColor(image, info, 12, 8, 2);
    DrawPixelColor(image, info, 13, 8, 1);
    DrawPixelColor(image, info, 14, 8, 0);

}

void ImageCreator::AddVersionInfo(QImage &image, std::vector<int> info)
{
    //Bottom Left Version Information Block
    int n1 = 0;
    int n2 = 0;
    for(int i = 5; i >= 0; i--){
        DrawPixelColor(image, info, n1++, i, nMods-9);
        DrawPixelColor(image, info, n1++, i, nMods-10);
        DrawPixelColor(image, info, n1++, i, nMods-11);

        DrawPixelColor(image, info, n2++, nMods-9, i);
        DrawPixelColor(image, info, n2++, nMods-10, i);
        DrawPixelColor(image, info, n2++, nMods-11, i);
    }
}

/**
 * @brief ImageCreator::PlaceDataBits
 * @param image
 *
 * 向图形中放置数据流，从右下角开始，依次向左向右放置。
 * 整个过程分为右、中、左三部分：
 *   1.放置右侧数据，范围是右上角位置探测图形（finder patterns）下方的一整块区域
 *   2.放置中间数据，范围是左右位置探测图形(包括分隔符和格式信息)中间的区域
 *   3.放置左侧数据， 位置是左上与左下位置探测图形之间的区域
 */
void ImageCreator::PlaceDataBits(QImage &image)
{
    int n = 0;
    //右侧区域
    for(int i = 1; i < 9; i += 2){
        //向上填充
        for(int j = 1; j <= nMods-9; j++){
            if(!IsLockModule(nMods-i, nMods-j)){
                DrawPixelColor(image, nMods-i, nMods-j, n);
                n++;
            }
            if(!IsLockModule(nMods-i-1, nMods-j)){
                DrawPixelColor(image, nMods-i-1, nMods-j, n);
                n++;
            }
        }
        //向下填充
        i += 2;
        for(int j = 9; j <= nMods-1; j++){
            if(!IsLockModule(nMods-i, j)){
                DrawPixelColor(image, nMods-i, j, n);
                n++;
            }
            if(!IsLockModule(nMods-i-1, j)){
                DrawPixelColor(image, nMods-i-1, j, n);
                n++;
            }
        }
    }

    //中间区域
    for(int i = 1; i <= nMods-17; i += 2){
        //向上填充
        for(int j = 1; j <= nMods; j++){
            if(!IsLockModule(nMods-8-i, nMods-j)){
                DrawPixelColor(image, nMods-8-i, nMods-j, n);
                n++;
            }
            if(!IsLockModule(nMods-9-i, nMods-j)){
                DrawPixelColor(image, nMods-9-i, nMods-j, n);
                n++;
            }
        }
        //向下填充
        i += 2;
        for(int j = 0; j <= nMods-1; j++){
            if(!IsLockModule(nMods-8-i, j)){
                DrawPixelColor(image, nMods-8-i, j, n);
                n++;
            }
            if(!IsLockModule(nMods-9-i, j)){
                DrawPixelColor(image, nMods-9-i, j, n);
                n++;
            }
        }
    }

    //左侧区域1
    for(int i = 1; i <= nMods-17; i++){
        if(!IsLockModule(8, nMods-8-i)){
            DrawPixelColor(image, 8, nMods-8-i, n);
            n++;
        }
        if(!IsLockModule(7, nMods-8-i)){
            DrawPixelColor(image, 7, nMods-8-i, n);
            n++;
        }
    }
    //左侧区域2
    for(int i = 9; i < nMods-8; i++){
        if(!IsLockModule(5, i)){
            DrawPixelColor(image, 5, i, n);
            n++;
        }
        if(!IsLockModule(4, i)){
            DrawPixelColor(image, 4, i, n);
            n++;
        }
    }
    //左侧区域3
    for(int i = 1; i <= nMods-17; i++){
        if(!IsLockModule(3, nMods-8-i)){
            DrawPixelColor(image, 3, nMods-8-i, n);
            n++;
        }
        if(!IsLockModule(2, nMods-8-i)){
            DrawPixelColor(image, 2, nMods-8-i, n);
            n++;
        }
    }
    //左侧区域4
    for(int i = 9; i < nMods-8; i++){
        if(!IsLockModule(1, i)){
            DrawPixelColor(image, 1, i, n);
            n++;
        }
        if(!IsLockModule(0, i)){
            DrawPixelColor(image, 0, i, n);
            n++;
        }
    }

    if(n == bitstream.size()){
        StringUtils::PRINT("数据长度正确 ", n);
    } else {
        StringUtils::PRINT("数据长度错误 ", n);
    }
}


bool ImageCreator::WithinFinderPatterns(int x, int y)
{
    if(x >= 0 && x <= 7 && y >= 0 && y <= 7){
        return true;
    }
    if(x >= 0 && x <= 7 && y >= (nMods-8) && y <= (nMods-1)){
        return true;
    }
    if(x >= (nMods-8) && x <= (nMods-1) && y >= 0 && y <= 7){
        return true;
    }

    return false;
}

bool ImageCreator::IsLockModule(int x, int y)
{
    auto result = std::find(lockModule.begin(), lockModule.end(), std::make_pair(x, y));

    if(result != lockModule.end()){
        return true;
    }
    return false;
}

void ImageCreator::DrawPixelColor(QImage &image, int x, int y, int n)
{
    if(n >= bitstream.size()){
        qDebug() << "imagecreator.cpp  DrawPixelColor() 0: 数据超出范围";
    }

    if(bitstream.at(n) == '1'){
        image.setPixelColor(x, y, value_b);
    } else if(bitstream.at(n) == '0'){
        image.setPixelColor(x, y, value_w);
    }
}

void ImageCreator::DrawPixelColor(QImage &image, std::vector<int> &info, int n, int x, int y)
{
    if(n >= info.size()){
        qDebug() << "imagecreator.cpp  DrawPixelColor() 1: 数据超出范围";
    }

    if(info.at(n) == 1){
        image.setPixelColor(x, y, value_b);
    } else if(info.at(n) == 0){
        image.setPixelColor(x, y, value_w);
    }
}

void ImageCreator::setVersion(int value)
{
    version = value;
}

void ImageCreator::setErrorLevel(char value)
{
    errorLevel = value;
}


void ImageCreator::setPic(const PictureInfo &value)
{
    pic = value;
}


}
